<?php

namespace app\common\traits\model;

use think\Model;
use think\Db;
use think\Loader;
use think\Session;
use Carbon\Carbon;
use think\Config;
use think\Exception;
use Lcobucci\JWT\Builder;
use Lcobucci\JWT\ValidationData;
use Lcobucci\JWT\Parser;
use app\common\model\Settings;
use app\common\model\Holidays;

trait TraitModel
{
    protected $pagesize         = 15;//列表分页大小
    protected $order            = 'id desc';
    protected static $loginuser = '';

    protected static function init()
    {
        self::afterInsert(function($model){
            self::tableLog('insert', $model->data);
        });
        self::afterUpdate(function($model){
            self::tableLog('update', $model->data);
        });
        self::afterDelete(function($model){
            self::tableLog('delete', $model->data);
        });
    }

    /**
     * 
     *
     * @return \think\Response
     */
    public static function getToken($user)
    {
        $token = (new Builder())->issuedBy('http://shsytour.cn')
                                ->canOnlyBeUsedBy('http://shsytour.cn')
                                ->identifiedBy(Config::get('key'), true)
                                //->expiresAt(time() + 3600)
                                ->with('user_info', $user)
                                ->getToken();

        return $token->__toString();
    }

    /**
     * 坐标转换
     * @param  [type] $lng [description]
     * @param  [type] $lat [description]
     * @return [type]      [description]
     */
    public static function translatPoint($lng, $lat)
    {
        $p = Db::query("SELECT GEOMFROMTEXT(?) LIMIT 1", ["POINT($lng $lat)"]);
        return current(current(array_values($p)));
    }
    /**
     * 写入一般操作日志
     * @return [type] [description]
     */
    protected static function log($type, $remark = '')
    {
        
    }
    /**
     * 表操作日志
     * @return [type] [description]
     */
    protected static function tableLog($operation, $data = [], $id = ''){}

    
    /**
     * 设置排序方法 支持链式
     * @param string $order [description]
     */
    public function setOrder($order = 'updated_at desc')
    {
        $this->order = $order;
        return $this;
    }
    protected function getOrder()
    {
        return $this->order;
    }
    /**
     * 解析querys参数
     * @param array $querys [description]
     */
    protected function setInfoListQuery($querys = [])
    {
        $_query = $this->db(false);

        $querys = array_filter($querys, function($q){
            if ($q !== '') {
                return true;
            }
        });
        
        if (array_key_exists('keyword', $querys)) {
            if (array_key_exists('searchfield', $querys)) {
                $querys[$querys['searchfield']] = ['like', '%%'.trim($querys['keyword']).'%%'];
            }else{
                $querys['name'] = ['like', '%%'.trim($querys['keyword']).'%%'];
            }
        }

        $querys = array_intersect_key($querys, array_flip($_query->getTableInfo('', 'fields')));

        if ($querys && is_array($querys)) {
            return $querys;
            //$_query->where($querys);
        }
        
        return ;
    }
    /**
     * 列表
     * @param  array   $querys [description]
     * @return [type]          [description]
     */
    public function getInfoList($querys = [], $with = null, $order = 'id desc')
    {
        if ($with && is_string($with) && strpos($with, ' ')) {
            $order = $with;
            $with = null;
        }
        
        return $this->where($this->setInfoListQuery($querys))->order($order)->with($with)->paginate($this->getPageSize(), false, ['query' => $querys]);
    }
    /**
     * 设置分页大小
     * @param int $size [description]
     */
    public function setPageSize($size = '')
    {
        if ($size!= '' && (is_int($size) && $size > 0)) {
            $this->pagesize = $size;
        }
        
        return $this;
    }
    /**
     * 获取数据分页大小
     * @return int [description]
     */
    private function getPageSize()
    {
        return $this->pagesize;
    }
    /**
     * 修改模型中间表信息
     * @param  [type] $relation [description]
     * @param  [type] $new_data [description]
     * @param  [type] $old_data [description]
     * @return [type]           [description]
     */
    public function updatePivot($relation, $new_data, $old_data = array())
    {
        $new_data = $new_data ? $new_data : array();
        $old_data = $old_data ? $old_data : array();

        $del_array = array_diff($old_data, $new_data);
        $add_array = array_diff($new_data, $old_data);

        if ($del_array) {
            $this->{$relation}()->detach($del_array);
        }
        if ($add_array) {
            $this->{$relation}()->saveAll($add_array);
        }
    }

    /**
     * 获取附近信息
     * @param  [type]  $lng      [description]
     * @param  [type]  $lat      [description]
     * @param  integer $distance [description]
     * @return [type]            [description]
     */
    public function distance($lng, $lat, $distance = 50)
    {
        return $this->field('(st_distance(point(lng, lat), point(:lng, :lat)) / 0.0111) AS `distance`')
        ->bind(['lng' => $lng, 'lat' => $lat])
        ->having('distance < '.$distance)
        ->order('distance ASC');
    }
    /**
     * 返回两点之间信息
     * @param  [type] $p1 [description]
     * @param  [type] $p2 [description]
     * @return [type]     [description]
     */
    public function range($p1, $p2)
    {
        $p1 = implode(' ', $p1);
        $p2 = implode(' ', $p2);

        return $this->where('Contains(Envelope(GeomFromText("LineString('.$p1.','.$p2.')")), point(lng,lat))');
    }
    /**
     * 计算时间差
     * @param  [type] $date_one [description]
     * @param  [type] $date_two [description]
     * @return [type]           [description]
     */
    public static function diffDays($date_one, $date_two, $abs = true)
    {
        if ($date_one instanceof Carbon) {
            $date_one = $date_one;
        }elseif (is_string($date_one)) {
            $date_one = Carbon::createFromFormat('Y-n-j', $date_one);
        }

        if ($date_two instanceof Carbon) {
            $date_two = $date_two;
        }elseif (is_string($date_two)) {
            $date_two = Carbon::createFromFormat('Y-n-j', $date_two);
        }

        return $date_one->diffInDays($date_two, $abs);
    }

    /**
     * 生成日期范围
     * @param  [type] $e [description]
     * @param  [type] $s [description]
     * @return [type]    [description]
     */
    public static function createDateRange($s, $e = null)
    {
        $e = $e ? $e : $s;
        if (is_string($s)) {
            $s = Carbon::createFromFormat('Y-n-j', $s);
        }elseif($s instanceof \DateTime){
            $s = $s;
        }
        $s = $s->diffInDays(Carbon::minValue());
        if (is_string($e)) {
            $e = Carbon::createFromFormat('Y-n-j', $e);
        }elseif($e instanceof \DateTime){
            $e = $e;
        }
        $e = $e->diffInDays(Carbon::minValue());

        $_time = range($s, $e, 1);
        array_walk_recursive($_time, function(&$date){$date = Carbon::minValue()->addDay($date)->toDateString();});
        return $_time;
    }

    public function safetyDate($date)
    {
        return Carbon::createFromFormat('Y-n-j', $date)->toDateString();
    }

    /**
     * 比较时间
     * @param  [type] $date_one [description]
     * @param  [type] $date_two [description]
     * @return [type]           [description]
     */
    public function comparisonDate($date_one, $date_two)
    {
        if (is_string($date_one)) {
            $date_one = Carbon::createFromFormat('Y-n-j', $date_one);
        }
        if (is_string($date_two)) {
            $date_two = Carbon::createFromFormat('Y-n-j', $date_two);
        }

        if ($date_one instanceof Carbon && $date_two instanceof Carbon) {
            if ($date_one->eq($date_two)) {
                return 'eq';
            }
            if ($date_one->gt($date_two)) {
                return 'gt';
            }
            return 'lt';
        }
        throw new Exception("Time format error", 1);  
    }
    /**
     * 返回真实时间
     * @param  [type]  $date [description]
     * @param  boolean $translated [description]
     */
    protected function getTrueDate(&$date, $translated = true)
    {
        $date = $translated ? Carbon::minValue()->addDay($date)->toDateString() : $date;
    }
    /**
     * 组合数组内数字 合并成段
     * @param  array  $dates [description]
     * @param  boolean $translated [description]
     * @return [type]        [description]
     */
    public static function combination($dates = [], $translated = true)
    {
        $result = [];
        $s = $e = $t = 0;
        if (empty($dates)) {
            return false;
        }
        $_dates = [];
        array_walk_recursive($dates, function($value,$key) use (&$_dates) {$_dates[] = $value;});
        $dates = [];
        $dates = array_unique($_dates);
        sort($dates);
        $len = count($dates);
        foreach ($dates as $key => $value) {
            if ($t == 0) {
                $s = $e = $value;
            }
            if ($len == 1) {
                $result[] = ['start'=>$s,'end'=>$e];
            }else{
                if ($len == $key + 1) {
                    $result[] = ['start'=>$s,'end'=>$value];
                }elseif ($len >= $key) {
                    $nex = $dates[$key + 1];
                    $tt = date('Y-m-d',strtotime("$value +1 day"));
                    //if (!($nex && $nex - $value == 1)) {
                    if (!($nex && $tt == $nex)) {
                        $e = $value;
                        $result[] = ['start'=>$s,'end'=>$e];
                        $s = $nex;
                    }
                }
            }
            $t = $value;
        }
        // if ($result && $translated) {
        //     array_walk_recursive($result, [$this, 'getTrueDate'], $translated);
        // }
        return $result;
    }
    /**
     * 获取假日系数
     * @param  [type] $date [description]
     * @return [type]       [description]
     */
    public static function getCoefficient($date = null, $transformation = true)
    {
        $d = (new Holidays)->holiday($date);
        if (empty($d)) {
            return $transformation ? (float) Holidays::$is_holiday[0] : 0;
        }
        if (key($d) !== 0) {
            $res = '';
            $res = $transformation ? (float) Holidays::$is_holiday[$d->is_holiday] : $d->is_holiday;
        }else{
            $res = [];
            foreach ($d as $value) {
                $res[$value->datetimes] = $transformation ? (float) Holidays::$is_holiday[$value->is_holiday] : $value->is_holiday;
            }
        }
        return $res;   
    }
    public static function getSettings($short_name, $field = '', $array = false)
    {
        if (is_bool($field)) {
            $array = $field;
            $field = '';
        }
        return (new Settings)->getSettings($short_name, $field, $array);
    }
    protected function getInvitation($len = 6, $type = 1)
    {
        switch ($type) {
            case 1:
                $codeSet = '0123456789';
                break;
            case 2:
                $codeSet = 'abcdefhijkmnpqrstuvwxyz';
                break;
            case 3:
                $codeSet = '2345678abcdefhijkmnpqrstuvwxyz';
                break;
            case 4:
                $codeSet = 'abcdefhijkmnpqrstuvwxyzABCDEFGHJKLMNPQRTUVWXY';
                break;
            case 5:
                $codeSet = '2345678abcdefhijkmnpqrstuvwxyzABCDEFGHJKLMNPQRTUVWXY';
                break;

            default:
                $codeSet = '2345678abcdefhijkmnpqrstuvwxyzABCDEFGHJKLMNPQRTUVWXY';
                break;
        }

        return substr(str_shuffle(str_repeat($codeSet, $len)), 0, $len);
    }

    /**
     * 生成uuid
     * @return uuid 返回uuid字符串
     */
    static public function uuid()
    {
        if (!function_exists('uuid_create')) {
            return \Ramsey\Uuid\Uuid::uuid4()->toString();
        }
        return uuid_create(); 
    }
    /**
     * [getLoginUserInfo 获取登陆者信息]
     * @param  string $field [description]
     * @return [type]        [description]
     */
    public static function getLoginUserInfo($field = '')
    {
        if (empty(self::$loginuser)) {
            $user_model = isset(self::$user_model) ? self::$user_model : 'Users';
            self::$loginuser = model($user_model)->getLoginUserInfo();
        }
        if ($field) {
            if (isset(self::$loginuser[$field])) {
                return self::$loginuser[$field]; 
            }
            return false;
        }
        return self::$loginuser;

        // self::$user_model = isset(self::$user_model) ? self::$user_model : 'Users';
        // if (model(self::$user_model)->checkLogin()) {
        //     if (empty(self::$loginuser)) {
        //         self::$loginuser = model(self::$user_model)->getLoginUserInfo();
        //     }
        //     if ($field) {
        //         if (isset(self::$loginuser[$field])) {
        //             return self::$loginuser[$field]; 
        //         }
        //         return false;
        //     }
        //     return self::$loginuser;
        // }else{
        //     throw new \Exception("no login", -99);  
        // }
    }

    public function __get($name)
    {
        try {
            return parent::__get($name);
            
        } catch (\Exception $e) {}

        try {
            return Loader::model($name);
        } catch (\Exception $e1) {
            if ($e) {
                throw $e;
            }
        }
    }

}
